#!/usr/bin/python
import tkinter as tk #import tkinter 三件套
import tkinter.font as tkFont
import tkinter.messagebox as tkMsgBox

def clr16(clr): #把RGB三元组转换成16进制码
    if (0 < clr[0] > 255)or(0 < clr[1] > 255)or(0 < clr[2] > 255): #如果RGB超出范围,则显示error
        tkMsgBox.showerror('error','颜色错误') #显示error
        return "#ffffff" #返回纯白色(255,255,255)

    r = str(hex(clr[0]))[2:].zfill(2) #转换r,g,b
    g = str(hex(clr[1]))[2:].zfill(2) #详见answers/2021/0801/show_color.py
    b = str(hex(clr[2]))[2:].zfill(2)
    clri16 = '#' + r + g + b #合并r,g,b并加上'#'

    return clri16 #返回16进制码

def Copy(string): #把内容复制到剪贴板(详见https://blog.csdn.net/My_CSDN_IT/article/details/114122199)
    r = tk.Tk()
    r.withdraw()
    r.clipboard_clear()
    r.clipboard_append(string)
    r.update()

def main(): #主函数
    top = tk.Tk() #没错,又是他们三---窗口
    top.title("颜色选择器") #标题
    top.resizable(False, False) #是否可拉伸
        
    gf = tkFont.Font(top, family="Arial", size = 20, weight=tkFont.BOLD) #字体一 great font
    mf = tkFont.Font(top, family="Monospace", size = 15) #字体二 middle font (关于字体详见附录一,119行)

    r=tk.IntVar() #RGB三元组---Red
    g=tk.IntVar() #Green
    b=tk.IntVar() #Blue

    def updateclrlb(): #更新clrlb的背景色,前景色,文字(clrlb99行)
        clrlb.configure(bg=clr16((int(r.get()/100*255), int(g.get()/100*255), int(b.get()/100*255))),
                        fg=clr16((int(255/(r.get()+1)), int(255/(g.get()+1)), int(255/(b.get()+1)))),
                        text=clr16((int(r.get()/100*255), int(g.get()/100*255), int(b.get()/100*255))))

    def Copy16(): #把16进制码复制到剪贴板(Copy函数第18行,clrl6函数第6行)
        Copy(clr16((int(r.get()/100*255), int(g.get()/100*255), int(b.get()/100*255)))) #传入16进制码
    #xxxxxx格式
    def CopyRGB(): #把RGB三元组复制到剪贴板(Copy函数18行)
        Copy('(' +str(int(r.get()/100*255)) + ',' + #传入RGB三元组
             str(int(g.get()/100*255)) + ',' + #(R,G,B)格式
             str(int(b.get()/100*255)) + ')')

    def OnSlider(v): #当滑动scaler时更新lbr的文字,scaler的凹槽颜色(lbr87行 scaler72行 updateclrlb37行)
        scaler.configure(troughcolor=clr16((int(r.get()/100*255),0,0))) #凹槽颜色
        lbr.configure(text="R:"+str(int(r.get()/100*255)).ljust(3,' ')) #lbr的文字
        updateclrlb()

    def OnSlideg(v): #当滑动scaleg时更新lbg的文字,scaleg的凹槽颜色(lbg88行 scaleg77行 updateclrlb37行)
        scaleg.configure(troughcolor=clr16((0,int(g.get()/100*255),0))) #凹槽颜色
        lbg.configure(text="G:"+str(int(g.get()/100*255)).ljust(3,' ')) #lbg的文字
        updateclrlb()

    def OnSlideb(v): #当滑动scaleb时更新lbb的文字,scaleb的凹槽颜色(lbb89行 scaleg82行 updateclrlb37行)
        scaleb.configure(troughcolor=clr16((0,0,int(b.get()/100*255)))) #凹槽颜色
        lbb.configure(text="B:"+str(int(b.get()/100*255)).ljust(3,' ')) #lbg的文字
        updateclrlb()

    frame1 = tk.Frame(top, pady=2) #创建三个frame
    frame1.pack()
    frame2 = tk.Frame(top, pady=2)
    frame2.pack()
    frame3 = tk.Frame(top, pady=2)
    frame3.pack()
    #以下三个scale结构类似,关于scale组件详见https://blog.csdn.net/nilvya/article/details/105710096,粗见第76行
    scaler = tk.Scale(frame1, orient=tk.HORIZONTAL, variable=r, from_=0, to=100,
                      length=255, showvalue=False, command=OnSlider, sliderlength=10,
                      sliderrelief=tk.GROOVE, relief=tk.RAISED, #关联r的scale
                      troughcolor=clr16((int(r.get()/100*255),0,0)))
    #创建一个横放,数值为0-100,长度255,滑块长度15,不显示滑块处数字,实时更新凹槽颜色,滑块风格GROOVE,凹槽风格RAISED的滑条(3个一样)
    scaleg = tk.Scale(frame2, orient=tk.HORIZONTAL, variable=g, from_=0, to=100,
                      length=255, showvalue=False, command=OnSlideg, sliderlength=10,
                      sliderrelief=tk.GROOVE, relief=tk.RAISED, #关联g的scale
                      troughcolor=clr16((0,int(g.get()/100*255),0)))

    scaleb = tk.Scale(frame3, orient=tk.HORIZONTAL, variable=b, from_=0, to=100,
                      length=255, showvalue=False, command=OnSlideb, sliderlength=10,
                      sliderrelief=tk.GROOVE, relief=tk.RAISED, #关联b的scale
                      troughcolor=clr16((0,0,int(b.get()/100*255))))
    #以下三个标签文本左对齐,且数字会补空格,补空格详见https://blog.csdn.net/weixin_42317507/article/details/93411132
    lbr = tk.Label(frame1, text="R:"+str(int(r.get()/100*255)).ljust(3,' '), width=5) #显示R,G,B的值--Red
    lbg = tk.Label(frame2, text="G:"+str(int(g.get()/100*255)).ljust(3,' '), width=5) #Green
    lbb = tk.Label(frame3, text="B:"+str(int(b.get()/100*255)).ljust(3,' '), width=5) #Blue

    lbr.pack(side=tk.LEFT) #统一pack掉
    lbg.pack(side=tk.LEFT)
    lbb.pack(side=tk.LEFT)
    
    scaler.pack() #统一pack掉
    scaleg.pack()
    scaleb.pack()

    clrlb = tk.Label(top, height=10,font=gf, #显示颜色的标签,无技术含量,只是字多
                     bg=clr16((int(r.get()/100*255), int(g.get()/100*255), int(b.get()/100*255))), #背景色
                     fg=clr16((int(255/(r.get()+1)), int(255/(g.get()+1)), int(255/(b.get()+1)))), #文字颜色
                     text=clr16((int(r.get()/100*255), int(g.get()/100*255), int(b.get()/100*255)))) #文字

    clrlb.pack(side=tk.TOP, fill=tk.X) #把x占满

    btnFrame=tk.Frame(top) #存放按钮的Frame
    btnFrame.pack(side=tk.TOP)

    btncp16=tk.Button(btnFrame, text="复制16进制码",font=mf, command=Copy16, width=10) #复制16进制码的按钮
    btncp16.pack(side=tk.LEFT) #Copy16函数第42行

    btncprgb=tk.Button(btnFrame, text="复制RGB三元组",font=mf, command=CopyRGB, width=10) #复制RGB三元组的按钮
    btncprgb.pack(side=tk.RIGHT) #CopyRGB函数第56行
    
    tileFrame=tk.Frame(top)
    tileFrame.pack(side=tk.TOP, anchor="s")
    
    tile=tk.Label(tileFrame, text="ColorChoicer v0.0.1 Powered by @King_haoqi", font=("Arial", 10),
                  fg="grey") #声明标签
    tile.pack(side=tk.BOTTOM)
    
    top.mainloop() #又是他

if __name__ == '__main__': #跑龙套
    main() #第25行
    
'''
附录一:
    Font:
    参数:
    family - 字体名称
    size - 字体大小
    weight - 可填(NORMAL, BOLD)(普通,加粗)
    slant - 可填ROMAN, ITALIC(正体，斜体)
    underline - 字体下划线(0无1有)
    overstrike - 字体删除线(0无1有)
附录二:
    关于此程序的其他思路
    1.ques:如何实现实时变更?
      ans:一直把要变的东西configure就好了
    2.ques:如何把100与255联系起来?
      ans:int(x/100*255)
    3.ques:如何能看见clrlb的文字?
      ans:用255去除当前rgb值,大部分情况下会生成当前颜色的背景色,但有遗留问题(见附录五)
附录三:
    本程序的制作步骤
    顺序
        1.实现基础功能
            a.实现小功能
            b.实现大概的效果(但有bug)
            c.一个一个干掉bug
            d.ok
        2.添加功能
        3.不知道/有bug?
            有->继续
            没->第5行
        4.问薛老师/CSDN,解决了?
            对->继续
            没->第4行
        5.调试美观(界面)
        6.是否有bug?
            有->第4行
            没->继续
        7.是否影响基础功能?
            没->第9行
            有->继续
        8.维护基础功能
            a.自己灭虫
            b.解决了?
                对->第9行
                没->继续
            c.CSDN/问薛老师
            d.->编号b
        9.完结了?
            对->继续
            没->第二行
        10.写注释&整理代码
        11.完结撒花
附录四:
    给薛老师的教学方法
    顺序:
        1.直接从24行开始解读
        2.先忽略函数
        3.到调用函数的时候去看函数
        4.有链接的时候看网页
        5.附录可以不看.也可以看
        6.补充:https://blog.csdn.net/nilvya/category_9896127.html是个宝藏博客
附录五:
    遗留问题
    当rgb值为(25,25,25)时,clrlb的文字颜色和背景色几乎相同,看不见字
附录六:
    参考资料总汇(加*为重点)
        *复制文本:https://blog.csdn.net/My_CSDN_IT/article/details/114122199
        *rgb转换:answers/2021/0801/show_color.py
        scale基础知识:answers/2021/0801/test_scale.py
        *scale扩展资料:https://blog.csdn.net/nilvya/article/details/105710096
        用空格补齐字符串:https://blog.csdn.net/weixin_42317507/article/details/93411132
        特别鸣谢:感谢薛老师对我的问题的解答,没有他,我不可能完成这个程序
        另:若此程序有bug,请劳驾在微信上告知King_haoqi
'''